fix(skirmish): Improve determinism for restarted games by resetting slot values#2373
fix(skirmish): Improve determinism for restarted games by resetting slot values#2373Caball009 wants to merge 3 commits intoTheSuperHackers:mainfrom
Conversation
|
| Filename | Overview |
|---|---|
| Core/GameEngine/Include/GameNetwork/GameInfo.h | Adds m_saveOriginalSetup flag and renames saveOffOriginalInfo to saveOriginalSetup; minor naming clarity concern on the getter. |
| Core/GameEngine/Source/GameNetwork/GameInfo.cpp | Implements m_saveOriginalSetup flag in reset() and saveOriginalSetup(); xfer load correctly calls saveOriginalSetup() to set the flag after restoring original values. |
| GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h | Adds toString(GameMode) free-function declaration; straightforward, no issues. |
| GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp | Core fix: startNewGame() now restores original slot values (color/pos/template = -1 for random) on restart so the logical seed is consumed identically to the first start; toString(GameMode) implementation covers all enum values. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[startNewGame called] --> B{loadingSaveGame?}
B -- Yes --> E[Skip slot setup]
B -- No --> C{m_saveOriginalSetup == TRUE?}
C -- "TRUE: first start" --> D["saveOriginalSetup\nstores color/pos/template as originals\nsets m_saveOriginalSetup = FALSE"]
C -- "FALSE: restart" --> F["Assert GAME_SKIRMISH\nRestore originals\nsetColor / setStartPos / setPlayerTemplate\nmay restore -1 for random slots"]
D --> G[populateRandomSideAndColor\npopulateRandomStartPosition]
F --> G
E --> G
G --> H[Logical seed consumed\nidentically on every start]
Prompt To Fix All With AI
This is a comment left during a code review.
Path: Core/GameEngine/Include/GameNetwork/GameInfo.h
Line: 104
Comment:
**Confusing boolean semantics on `getSaveOriginalSetup()`**
The field `m_saveOriginalSetup` is initialised to `TRUE` (meaning "not yet saved") and flipped to `FALSE` after `saveOriginalSetup()` runs. This causes the caller in `GameLogic.cpp` to use a double-negative: `if (!slot->getSaveOriginalSetup())` to detect the restart path.
Consider naming the field/getter to reflect the completed state, which reads naturally at the call-site:
```suggestion
Bool isOriginalSetupSaved() const { return m_saveOriginalSetup; }
```
And rename the member to `m_isOriginalSetupSaved`, initialised to `FALSE` in `reset()` and set to `TRUE` in `saveOriginalSetup()`. Then `GameLogic.cpp` becomes `if (slot->isOriginalSetupSaved())` — immediately clear that this is the restart path.
How can I resolve this? If you propose a fix, please make it concise.Reviews (4): Last reviewed commit: "Reset randomized slot values." | Re-trigger Greptile
GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp
Outdated
Show resolved
Hide resolved
GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp
Outdated
Show resolved
Hide resolved
xezon
left a comment
There was a problem hiding this comment.
Greptile is still complaining about something?
Yes, that was a good point. I think it could have affected the randomization of AI players if a game was loaded from inside another game or replay. GeneralsGameCode/Core/GameEngine/Source/GameNetwork/GameInfo.cpp Lines 1594 to 1600 in 637dbba It should work correctly now because Replication in Generals still needs doing. |
| } | ||
| else | ||
| { | ||
| m_saveOffOriginalInfo = TRUE; |
There was a problem hiding this comment.
The reason for this is unintuitive.
Perhaps it would be better to have 2 versions of saveOffOriginalInfo, one used in the xfer and the other on new game start? Or just test the boolean outside of saveOffOriginalInfo.
That may also be a good opportunity to fix the name of saveOffOriginalInfo, for example saveOriginalSetup.
e5d4698 to
0239428
Compare
|
I can replicate in Generals unless there are other changes desired. |
Restarted skirmish games may not start with the same logical seed value as the first start. This depends on whether there are players with a random color / position / faction. Those random values are determined by using and updating the logical seed on the first start, after which the random values are stored. That means that for restarted games the logical seed isn't used or updated for those purposes. This PR resets those values to improve determinism for restarted games.
You can put a breakpoint after
GameLogic::startNewGameand compare the values oftheGameLogicSeedfor the first start and following starts and see how the values for the first start deviate from restarts.TODO: